package com.anupam;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

/**
 * This class reads the input file containing the JSON to be parsed. Each entry
 * has a dimension field describing the size of the matrix and a state array
 * containing the starting state of each cell.
 * 
 * @NotThreadSafe
 * 
 * @author anupamsaini@gmail.com (Anupam Saini)
 * 
 */
public class PatternReader {

        /**
         * This class represents a M*N matrix and the initial state of its each
         * cell.
         * 
         */
        public class Pattern {
                /**
                 * Size of the M*N matrix
                 */
                private List<Integer> dimension;

                /**
                 * State of the each cell, 1 indicates alive 0 indicates dead cell.
                 */
                private List<Integer> state;

                public Pattern(List<Integer> dimension, List<Integer> state) {
                        this.dimension = dimension;
                        this.state = state;
                }

                public List<Integer> getDimension() {
                        return dimension;
                }

                public List<Integer> getState() {
                        return state;
                }

                @Override
                public String toString() {
                        return " X: " + dimension.size() + " Y: " + state.size();
                }

        }

        /**
         * Reads a file stream and converts it into an object representation of
         * {@link Pattern} type.
         * 
         * @param in
         *            The file stream containing the matrix dimension and state.
         * @return A List of all the matrix read from the file.
         * @throws IOException
         */
        public List<Pattern> readJsonStream(InputStream in) throws IOException {
                JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
                try {
                        return readPatternsArray(reader);
                } finally {
                        reader.close();
                }
        }

        private List<Pattern> readPatternsArray(JsonReader reader)
                        throws IOException {
                List<Pattern> patterns = new ArrayList<Pattern>();

                reader.beginArray();
                while (reader.hasNext()) {
                        patterns.add(readPattern(reader));
                }
                reader.endArray();
                return patterns;
        }

        /**
         * Read a pattern string of following format into an object of type
         * {@link Pattern}. For instance a pattern read from input stream can be
         * like : { "dimension":[2,2], "state":[1,1,1,1] }
         * 
         * 
         * @param reader
         * @return An object of type {@link Pattern}.
         * @throws IOException
         */
        private Pattern readPattern(JsonReader reader) throws IOException {
                List<Integer> dimension = null;
                List<Integer> state = null;

                reader.beginObject();
                while (reader.hasNext()) {
                        String name = reader.nextName();
                        if (name.equals("dimension") && reader.peek() != JsonToken.NULL) {
                                dimension = readIntegersArray(reader);
                        } else if (name.equals("state") && reader.peek() != JsonToken.NULL) {
                                state = readIntegersArray(reader);
                        }
                }
                reader.endObject();
                return new Pattern(dimension, state);
        }

        /**
         * Reads an array of comma separated integers to a List. For instance the
         * value of state key "state":[1,1,1,1]
         * 
         * @param reader
         * @return A list of integers.
         * @throws IOException
         */
        private List<Integer> readIntegersArray(JsonReader reader)
                        throws IOException {
                List<Integer> integers = new ArrayList<Integer>();

                reader.beginArray();
                while (reader.hasNext()) {
                        integers.add(reader.nextInt());
                }
                reader.endArray();
                return integers;
        }

}